from django.db import connection, models
from django.apps import apps

from libs.db import BaseModel
from libs.enums import PartnerType, Authorizer


class DatawareService:
    def create_dynamic_model(self, table_name, fields, exist=False):
        class Meta:
            db_table = table_name

        attrs = {
            '__module__': 'datacenter.models',
            'Meta': Meta
        }

        for field_name, field_type in fields.items():
            attrs[field_name] = field_type

        model_class = type(table_name, (BaseModel,), attrs)

        if not exist:
            with connection.schema_editor() as schema_editor:
                schema_editor.create_model(model_class)

        return model_class

    def init_tables(self, certificate):
        if certificate.authorizer != Authorizer.OTHER_SIDE.value or certificate.connection.partner.type != PartnerType.ORG.value:
            return
        entities = certificate.data.get('entities', [])
        for entity in entities:
            key = entity.get('key')
            fields = entity.get('fields')
            primary_key = entity.get('primary_key')
            if not key or not fields:
                continue
            exist = self.is_table_exist(certificate, key)
            model_fields = {}
            for field in fields:
                if field['field'] == primary_key:
                    model_fields[field['field']] = models.CharField(field.get('lable'), max_length=200, primary_key=True)
                else:
                    model_fields[field['field']] = models.TextField(field.get('lable'), null=True, blank=True)
            self.create_dynamic_model(self.get_table_name(certificate, key), model_fields, exist=exist)

    def get_table_name(self, certificate, entity_key):
        return f'datacenter_{certificate.connection.partner_id}_{entity_key}'

    def is_table_exist(self, certificate, entity_key):
        table_name = self.get_table_name(certificate, entity_key)
        existing_tables = connection.introspection.table_names()
        return table_name in existing_tables

    def get_model(self, certificate, entity_key):
        try:
            apps.get_model('datacenter', self.get_table_name(certificate, entity_key))
        except Exception:
            self.init_tables(certificate)
        return apps.get_model('datacenter', self.get_table_name(certificate, entity_key))


dataware_service = DatawareService()
